# auto_publish/views.py
import os
import json
import time
import requests
from datetime import datetime
from django.conf import settings
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator
from django.views import View
from .models import VideoPublishTask
from django.contrib.auth.models import User
from django.core.paginator import Paginator
from django.db.models import Q

# 确保这些库已安装: pip install DrissionPage pyautogui pyperclip
try:
    from DrissionPage import ChromiumPage
    import pyautogui
    import pyperclip

    DRSSIONPAGE_AVAILABLE = True
except ImportError:
    DRSSIONPAGE_AVAILABLE = False

# 设置视频保存路径为Django媒体文件路径
VIDEO_SAVE_PATH = os.path.join(settings.MEDIA_ROOT, 'videos')
os.makedirs(VIDEO_SAVE_PATH, exist_ok=True)


def download_video(url, save_path, task=None):
    """下载视频到本地"""
    try:
        if task:
            task.status = 'downloading'
            task.save()

        file_name = url.split("/")[-1] if "." in url.split("/")[
            -1] else f"{datetime.now().strftime('%Y%m%d%H%M%S')}.mp4"
        file_path = os.path.join(save_path, file_name)

        print(f"开始下载视频：{url}")
        response = requests.get(url, stream=True, timeout=30)
        total_size = int(response.headers.get('content-length', 0))
        downloaded = 0

        with open(file_path, "wb") as f:
            for chunk in response.iter_content(chunk_size=1024 * 1024):
                if chunk:
                    f.write(chunk)
                    downloaded += len(chunk)
                    if total_size > 0 and task:
                        progress = int((downloaded / total_size) * 100)
                        print(f"下载进度: {progress}%")

        print(f"视频下载成功，保存至：{file_path}")
        return file_path
    except Exception as e:
        print(f"视频下载失败：{str(e)}")
        return None


def upload_with_pyautogui(file_path):
    """使用pyautogui模拟键盘操作上传文件"""
    try:
        # 复制文件路径到剪贴板
        pyperclip.copy(file_path)
        time.sleep(1)

        # 模拟键盘操作粘贴文件路径
        pyautogui.hotkey('ctrl', 'v')
        time.sleep(1)

        # 按回车确认
        pyautogui.press('enter')
        time.sleep(3)

        print("已尝试使用键盘操作上传文件")
        return True
    except Exception as e:
        print(f"使用键盘操作上传文件失败：{e}")
        return False


def click_publish_button_precise(page):
    """精准定位发布按钮"""
    print("尝试精准定位发布按钮...")

    # 等待页面加载完成
    time.sleep(3)

    # 方法1: 使用精确的CSS选择器
    try:
        publish_btn = page.ele('css:button.button-dhlUZE.primary-cECiOJ.fixed-J9O8Yw', timeout=5)
        if publish_btn:
            print("通过精确CSS选择器找到发布按钮")
            publish_btn.click()
            print("已点击发布按钮")
            return True
    except Exception as e:
        print(f"精确CSS选择器失败: {e}")

    # 方法2: 使用XPath定位文本和类名
    try:
        publish_btn = page.ele('xpath://button[contains(@class, "button-dhlUZE") and contains(text(), "发布")]',
                               timeout=3)
        if publish_btn:
            print("通过XPath找到发布按钮")
            publish_btn.click()
            print("已点击发布按钮")
            return True
    except Exception as e:
        print(f"XPath定位失败: {e}")

    # 方法3: 使用JavaScript直接操作DOM
    try:
        js_code = '''
        var buttons = document.querySelectorAll('button.button-dhlUZE.primary-cECiOJ.fixed-J9O8Yw');
        if (buttons.length > 0) {
            buttons[0].click();
            return true;
        }

        var allButtons = document.querySelectorAll('button');
        for (var i = 0; i < allButtons.length; i++) {
            if (allButtons[i].textContent === '发布') {
                allButtons[i].click();
                return true;
            }
        }

        return false;
        '''

        result = page.run_js(js_code)
        if result:
            print("通过JavaScript点击了发布按钮")
            return True
        else:
            print("JavaScript未找到发布按钮")
    except Exception as e:
        print(f"JavaScript执行失败: {e}")

    print("所有精准定位方法均失败")
    return False


def publish_to_douyin(video_path, title, description, tags, task=None):
    """使用DrissionPage发布视频到抖音网页版"""
    if not DRSSIONPAGE_AVAILABLE:
        print("DrissionPage库未安装，无法进行自动发布")
        return False

    if task:
        task.status = 'publishing'
        task.save()

    page = ChromiumPage()
    SCAN_WAIT_TIME = 30

    try:
        # 1. 打开抖音创作平台
        print("打开抖音创作平台...")
        page.get("https://creator.douyin.com/creator-micro/home")

        # 2. 等待扫码登录
        print("请在30秒内使用抖音APP扫码登录...")
        time.sleep(30)

        # 3. 验证登录状态
        if not page.ele('text:创作服务平台', timeout=10):
            print("登录失败，请检查扫码是否成功")
            return False

        # 4. 进入发布页面
        print("进入视频发布页面...")
        page.ele('text:发布视频').click()
        page.wait.load_start()

        # 5. 上传视频 - 尝试多种方法
        print("上传视频中...")

        # 方法1: 尝试点击上传区域
        try:
            upload_area = page.ele('text:点击上传', timeout=10) or page.ele('text:或将视频拖到此处', timeout=5)
            if upload_area:
                upload_area.click()
                print("已点击上传区域")
                time.sleep(2)

                # 使用pyautogui上传文件
                upload_with_pyautogui(video_path)
        except:
            print("无法点击上传区域，尝试其他方法")

        # 方法2: 尝试直接设置文件输入框
        try:
            upload_ele = page.ele('tag:input@@type=file', timeout=5)
            if upload_ele:
                # 使用JavaScript设置文件路径
                js_escaped_path = video_path.replace('\\', '\\\\')
                js_code = f'''
                var input = arguments[0];
                input.value = "{js_escaped_path}";
                var event = new Event('change', {{ bubbles: true }});
                input.dispatchEvent(event);
                '''
                page.run_js(js_code, upload_ele)
                print("已尝试直接设置文件路径")
        except:
            print("无法直接设置文件路径")

        # 等待上传完成
        print("视频上传中，请耐心等待...")
        time.sleep(30)

        # 6. 填写视频信息
        print("填写视频信息...")

        # 标题 - 尝试多种选择器
        try:
            title_selectors = [
                'css:[placeholder*="标题"]',
                'css:[placeholder*="请输入"]',
                'css:div[contenteditable="true"]',
                'xpath://div[@contenteditable="true"]',
                'css:textarea',
                'tag:textarea'
            ]

            for selector in title_selectors:
                try:
                    title_ele = page.ele(selector, timeout=2)
                    if title_ele:
                        title_ele.input(title)
                        print("标题填写成功")
                        break
                except:
                    continue
            else:
                print("未找到标题输入框")
        except Exception as e:
            print(f"填写标题时出错：{e}")

        # 描述 - 尝试多种选择器
        try:
            desc_selectors = [
                'css:[placeholder*="描述"]',
                'css:[placeholder*="添加描述"]',
                'css:textarea',
                'tag:textarea',
                'class:editor-kit-container',
                'class:zone-container',
                'class:editor',
                'css:div[contenteditable="true"]'
            ]

            for selector in desc_selectors:
                try:
                    desc_ele = page.ele(selector, timeout=2)
                    if desc_ele:
                        if 'contenteditable' in selector:
                            js_code = f'''
                            var editor = arguments[0];
                            editor.innerText = "{description}";
                            '''
                            page.run_js(js_code, desc_ele)
                        else:
                            desc_ele.input(description)
                        print("描述填写成功")
                        break
                except:
                    continue
            else:
                print("未找到描述输入框")
        except Exception as e:
            print(f"填写描述时出错：{e}")

        # 话题标签
        if tags:
            try:
                tag_selectors = [
                    'css:[placeholder*="话题"]',
                    'css:[placeholder*="添加话题"]',
                    'class:topic-input'
                ]

                for selector in tag_selectors:
                    try:
                        tag_input = page.ele(selector, timeout=2)
                        if tag_input:
                            tag_text = " ".join([f"#{tag}" for tag in tags])
                            tag_input.input(tag_text)
                            print("话题标签填写成功")
                            break
                    except:
                        continue
                else:
                    print("未找到话题输入框，跳过添加话题")
            except Exception as e:
                print(f"填写话题标签时出错：{e}")

        # 7. 发布视频 - 使用精准定位方法
        print("尝试发布视频...")

        # 等待页面可能出现的任何弹窗或加载
        time.sleep(5)

        # 使用精准定位方法点击发布按钮
        if click_publish_button_precise(page):
            print("发布按钮点击成功")

            # 等待用户扫码验证
            print(f"请在 {SCAN_WAIT_TIME} 秒内完成扫码验证...")
            time.sleep(SCAN_WAIT_TIME)

            # 检查是否发布成功
            try:
                success_indicators = [
                    'text:发布成功',
                    'text:内容已提交',
                    'text:审核中',
                    'text:发布完成'
                ]

                for indicator in success_indicators:
                    if page.ele(indicator, timeout=5):
                        print("视频发布成功!")
                        return True
            except:
                print("未检测到明确的成功提示，请手动确认发布状态")

            return True
        else:
            print("未能点击发布按钮，请手动操作")
            return False

    except Exception as e:
        print(f"发布过程出错：{str(e)}")
        return False
    finally:
        # 不关闭页面，让用户可以看到扫码界面
        print("页面保持打开状态，请手动关闭浏览器")


@method_decorator(csrf_exempt, name='dispatch')
class PublishVideoView(View):
    def post(self, request):
        try:
            data = json.loads(request.body)
            video_url = data.get('video_url')
            title = data.get('title', '默认标题')
            description = data.get('description', '')
            tags = data.get('tags', [])

            # 创建一个默认用户用于测试（实际应用中应从request.user获取）
            user, created = User.objects.get_or_create(username='default_user')

            if not video_url:
                return JsonResponse({'error': '缺少视频URL'}, status=400)

            # 创建任务记录
            task = VideoPublishTask.objects.create(
                user=user,
                video_url=video_url,
                title=title,
                description=description,
                tags=tags,
                save_path=VIDEO_SAVE_PATH
            )

            # 下载视频
            video_path = download_video(video_url, VIDEO_SAVE_PATH, task)
            if not video_path:
                task.status = 'failed'
                task.save()
                return JsonResponse({'error': '视频下载失败', 'task_id': task.id}, status=500)

            # 更新保存路径
            task.save_path = video_path
            task.save()

            # 发布视频
            success = publish_to_douyin(video_path, title, description, tags, task)

            # 更新任务状态
            task.status = 'success' if success else 'failed'
            task.save()

            if success:
                return JsonResponse({
                    'message': '视频发布成功',
                    'task_id': task.id,
                    'status': task.status
                })
            else:
                return JsonResponse({
                    'error': '视频发布失败',
                    'task_id': task.id,
                    'status': task.status
                }, status=500)

        except Exception as e:
            return JsonResponse({'error': str(e)}, status=500)


class TaskStatusView(View):
    def get(self, request, task_id):
        try:
            task = VideoPublishTask.objects.get(id=task_id)
            return JsonResponse({
                'task_id': task.id,
                'status': task.status,
                'title': task.title,
                'created_at': task.created_at,
                'updated_at': task.updated_at
            })
        except VideoPublishTask.DoesNotExist:
            return JsonResponse({'error': '任务不存在'}, status=404)


class VideoListView(View):
    def get(self, request):
        try:
            # 获取分页参数
            page = int(request.GET.get('page', 1))
            size = int(request.GET.get('size', 10))

            # 获取搜索参数
            search = request.GET.get('search', '')

            # 构建查询
            queryset = VideoPublishTask.objects.all().order_by('-created_at')

            # 如果有搜索参数，进行过滤
            if search:
                queryset = queryset.filter(
                    Q(title__icontains=search) |
                    Q(description__icontains=search)
                )

            # 分页处理
            paginator = Paginator(queryset, size)
            page_obj = paginator.get_page(page)

            # 构造返回数据
            videos = []
            for task in page_obj:
                videos.append({
                    'id': task.id,
                    'title': task.title,
                    'description': task.description,
                    'video_url': task.video_url,
                    'tags': task.tags,
                    'status': task.status,
                    'created_at': task.created_at,
                    'updated_at': task.updated_at
                })

            return JsonResponse({
                'videos': videos,
                'total': paginator.count,
                'page': page,
                'size': size,
                'pages': paginator.num_pages
            })
        except Exception as e:
            return JsonResponse({'error': str(e)}, status=500)
